package cz.muni.fi.pb138.accountingRecords.web;

import cz.muni.fi.pb138.accountingRecords.Invoice;
import cz.muni.fi.pb138.accountingRecords.InvoiceManagerImpl;
import cz.muni.fi.pb138.accountingRecords.PaymentManagerImpl;
import cz.muni.fi.pb138.accountingRecords.Payment;
import java.io.IOException;
import java.text.Format;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.w3c.dom.Document;

public class ActionServlet extends HttpServlet {

    static final String ACTION_ADD_PAYMENT = "/AddPayment";
    static final String ACTION_EDIT_PAYMENT = "/EditPayment";
    static final String ACTION_EDIT_ATTRIBUTES = "/EditAttributes";
    static final String ACTION_REMOVE_PAYMENT = "/RemovePayment";
    static final String ACTION_SHOW_PAYMENTS = "/ShowPayments";
    static final String ACTION_ADD_INVOICE = "/AddInvoice";
    static final String ACTION_EDIT_INVOICE = "/EditInvoice";
    static final String ACTION_REMOVE_INVOICE = "/RemoveInvoice";
    static final String ACTION_SHOW_INVOICES = "/ShowInvoices";
    static final String ACTION_PREPARE_TAX = "/PrepareTax";
    static final String ACTION_CONFIRM_REMOVE_PAYMENT = "/ConfirmRemovePayment";
    static final String ACTION_CONFIRM_REMOVE_INVOICE = "/ConfirmRemoveInvoice";
    static final String ACTION_INVOICE_DETAIL = "/InvoiceDetail";
    static final String ACTION_EDIT_ATTRIBUTES_INVOICE = "/EditAttributesInvoice";
    static final String ATTRIBUTE_EDIT_PAYMENT = "payment";
    static final String ATTRIBUTE_EDIT_INVOICE = "invoice";
    static final String ATTRIBUTE_PAYMENTS = "payments";
    static final String ATTRIBUTE_PAYMENT_FORM = "paymentForm";
    static final String ATTRIBUTE_INVOICES = "invoices";
    static final String ATTRIBUTE_INVOICE_FORM = "invoiceForm";
    static final String ATTRIBUTE_ERROR = "error";
    static final String ATTRIBUTE_FROM_DATE = "fromDate";
    static final String ATTRIBUTE_TO_DATE = "toDate";
    static final String ATTRIBUTE_SUM_PAYMENTS = "sumPayments";
    static final String ATTRIBUTE_SUM_INVOICES = "sumInvoices";
    static final String ATTRIBUTE_XML_DOCUMENT = "xmlDoc";
    static final String ATTRIBUTE_PATH = "path";
    static final String ATTRIBUTE_YEAR = "year";
    static final String ATTRIBUTE_TRANSFORMED_XML = "transformedXml";
    static final String JSP_ADD_PAYMENT = "/WEB-INF/jsp/addPayment.jsp";
    static final String JSP_EDIT_ATTRIBUTES = "/WEB-INF/jsp/editAttributes.jsp";
    static final String JSP_EDIT_ATTRIBUTES_INVOICE = "/WEB-INF/jsp/editAttributesInvoice.jsp";
    static final String JSP_LIST_PAYMENTS = "/WEB-INF/jsp/listPayments.jsp";
    static final String JSP_EDIT_PAYMENT = "/WEB-INF/jsp/editPayment.jsp";
    static final String JSP_REMOVE_PAYMENT = "/WEB-INF/jsp/removePayment.jsp";
    static final String JSP_SHOW_PAYMENTS = "/WEB-INF/jsp/showPayments.jsp";
    static final String JSP_ADD_INVOICE = "/WEB-INF/jsp/addInvoice.jsp";
    static final String JSP_EDIT_INVOICE = "/WEB-INF/jsp/editInvoice.jsp";
    static final String JSP_REMOVE_INVOICE = "/WEB-INF/jsp/removeInvoice.jsp";
    static final String JSP_SHOW_INVOICES = "/WEB-INF/jsp/showInvoices.jsp";
    static final String JSP_PREPARE_TAX = "/WEB-INF/jsp/prepareTax.jsp";
    static final String JSP_CONFIRM_REMOVE_PAYMENT = "/WEB-INF/jsp/confirmRemovePayment.jsp";
    static final String JSP_CONFIRM_REMOVE_INVOICE = "/WEB-INF/jsp/confirmRemoveInvoice.jsp";
    static final String JSP_INVOICE_DETAIL = "/WEB-INF/jsp/invoiceDetail.jsp";
    private PaymentManagerImpl paymentManager = new PaymentManagerImpl("/db/accounting-records/payments", "admin", "admin");
    private InvoiceManagerImpl invoiceManager = new InvoiceManagerImpl("/db/accounting-records/invoices", "admin", "admin");
/*
 * Method for inserting payment into database. 
 * @param request request from page
 * @param response response to page
 * @throws ServletException
 * @throws IOException 
 */
    private void addPayment(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        if (request.getMethod().equals("POST")) {

            if (request.getParameter("cancel") != null) {
                response.sendRedirect(request.getContextPath());
                return;
            }
            StringBuilder errors = new StringBuilder();
            PaymentForm paymentForm = PaymentForm.extractFromRequest(request);
            Payment payment = paymentForm.validateAndToPayment(errors);
            if (payment == null) {
                request.setAttribute(ATTRIBUTE_ERROR, errors.toString());
                request.setAttribute(ATTRIBUTE_PAYMENT_FORM, paymentForm);
                request.getRequestDispatcher(JSP_ADD_PAYMENT).forward(request, response);
            } else {
                paymentManager.addPayment(payment);
                response.sendRedirect(request.getContextPath());
            }
        } else {
            request.setAttribute(ATTRIBUTE_PAYMENT_FORM, new PaymentForm());
            request.getRequestDispatcher(JSP_ADD_PAYMENT).forward(request, response);
        }
    }
/*
 * Method which lists payments in database for further editing. 
 * @param request request from page
 * @param response response to page
 * @throws ServletException
 * @throws IOException 
 */
    private void editPayment(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setAttribute(ATTRIBUTE_PAYMENTS, paymentManager.getPaymentsForPeriod(new Date(Long.MIN_VALUE), new Date(Long.MAX_VALUE)));
        request.getRequestDispatcher(JSP_EDIT_PAYMENT).forward(request, response);
    }
/*
 * Method for editing payments in database. 
 * @param request request from page
 * @param response response to page
 * @throws ServletException
 * @throws IOException 
 */
    private void editAttributes(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        if (request.getMethod().equals("GET")) {
            String id = request.getParameter("id");
            Payment payment = paymentManager.getPayment(id);

            if (request.getParameter("cancel") != null) {
                response.sendRedirect(request.getContextPath());
                return;
            }
            StringBuilder errors = new StringBuilder();
            request.setAttribute(ATTRIBUTE_ERROR, errors.toString());
            SimpleDateFormat foramtter = new SimpleDateFormat("dd/MM/yyyy");
            request.setAttribute("niceDate", foramtter.format(payment.getTransferDate()));
            request.setAttribute(ATTRIBUTE_EDIT_PAYMENT, payment);
            request.getRequestDispatcher(JSP_EDIT_ATTRIBUTES).forward(request, response);

            // response.sendRedirect(request.getContextPath());
        }
        if (request.getMethod().equals("POST")) {
            if (request.getParameter("cancel") != null) {
                response.sendRedirect(request.getContextPath());
                return;
            }
            StringBuilder errors = new StringBuilder();
            PaymentForm paymentForm = PaymentForm.extractFromRequest(request);
            Payment payment = paymentForm.validateAndToPayment(errors);

            if (payment == null) {
                request.setAttribute(ATTRIBUTE_ERROR, errors.toString());

                request.setAttribute(ATTRIBUTE_ERROR, this);
                request.setAttribute(ATTRIBUTE_EDIT_PAYMENT, paymentForm);
                request.getRequestDispatcher(JSP_EDIT_ATTRIBUTES).forward(request, response);
            } else {
                payment.setId(request.getParameter("id"));
                paymentManager.updatePayment(payment);
                response.sendRedirect(request.getContextPath());
            }
        }
    }
/*
 * Method for removing payment from database. 
 * @param request request from page
 * @param response response to page
 * @throws ServletException
 * @throws IOException 
 */
    private void removePayment(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setAttribute(ATTRIBUTE_PAYMENTS, paymentManager.getPaymentsForPeriod(new Date(Long.MIN_VALUE), new Date(Long.MAX_VALUE)));
        request.getRequestDispatcher(JSP_REMOVE_PAYMENT).forward(request, response);
    }
/*
 * Method to show payment for delete before actual delete and ask user to confirm.
 * @param request request from page
 * @param response response to page
 * @throws ServletException
 * @throws IOException 
 */
    private void confirmRemovePayment(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        if (request.getMethod().equals("GET")) {
            String id = request.getParameter("id");
            Payment payment = paymentManager.getPayment(id);

            if (request.getParameter("cancel") != null) {
                response.sendRedirect(request.getContextPath());
                return;
            }
            StringBuilder errors = new StringBuilder();
            request.setAttribute(ATTRIBUTE_ERROR, errors.toString());
            SimpleDateFormat foramtter = new SimpleDateFormat("dd/MM/yyyy");
            request.setAttribute("stringDate", foramtter.format(payment.getTransferDate()));
            request.setAttribute(ATTRIBUTE_EDIT_PAYMENT, payment);
            request.getRequestDispatcher(JSP_CONFIRM_REMOVE_PAYMENT).forward(request, response);

            //response.sendRedirect(request.getContextPath());
        }
        if (request.getMethod().equals("POST")) {
            if (request.getParameter("cancel") != null) {
                response.sendRedirect(request.getContextPath());
                return;
            }
            StringBuilder errors = new StringBuilder();
            paymentManager.removePayment(request.getParameter("id"));
            response.sendRedirect(request.getContextPath());
        }
    }
/*
 * Method to list all payments in databse. 
 * @param request request from page
 * @param response response to page
 * @throws ServletException
 * @throws IOException 
 */
    private void showPayments(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, ParseException {
        //request.setAttribute(ATTRIBUTE_FROM_DATE, request.getParameter("fromDate"));
        //request.setAttribute(ATTRIBUTE_TO_DATE, request.getParameter("toDate"));
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
        request.setAttribute(ATTRIBUTE_PAYMENTS, paymentManager.getPaymentsForPeriod(sdf.parse(request.getParameter("fromDate")), sdf.parse(request.getParameter("toDate"))));
        request.getRequestDispatcher(JSP_SHOW_PAYMENTS).forward(request, response);
    }
/*
 * Method for inserting invoice into database. 
 * @param request request from page
 * @param response response to page
 * @throws ServletException
 * @throws IOException 
 */
    private void addInvoice(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        if (request.getMethod().equals("POST")) {

            if (request.getParameter("cancel") != null) {
                response.sendRedirect(request.getContextPath());
                return;
            }
            StringBuilder errors = new StringBuilder();
            InvoiceForm invoiceForm = InvoiceForm.extractFromRequest(request);
            Invoice invoice = invoiceForm.validateAndToInvoice(errors);
            if (invoice == null) {
                request.setAttribute(ATTRIBUTE_ERROR, errors.toString());
                request.setAttribute(ATTRIBUTE_INVOICE_FORM, invoiceForm);
                request.getRequestDispatcher(JSP_ADD_INVOICE).forward(request, response);
            } else {
                invoiceManager.addInvoice(invoice);
                response.sendRedirect(request.getContextPath());
            }
        } else {
            request.setAttribute(ATTRIBUTE_INVOICE_FORM, new InvoiceForm());
            request.getRequestDispatcher(JSP_ADD_INVOICE).forward(request, response);
        }
    }
/*
 * Method which lists invoices in database for further editing. 
 * @param request request from page
 * @param response response to page
 * @throws ServletException
 * @throws IOException 
 */
    private void editInvoice(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setAttribute(ATTRIBUTE_INVOICES, invoiceManager.getInvoicesForPeriod(new Date(Long.MIN_VALUE), new Date(Long.MAX_VALUE)));
        request.getRequestDispatcher(JSP_EDIT_INVOICE).forward(request, response);
    }
/*
 * Method for editing invoice in database. 
 * @param request request from page
 * @param response response to page
 * @throws ServletException
 * @throws IOException 
 */
    private void editAttributesInvoice(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        if (request.getMethod().equals("GET")) {
            String id = request.getParameter("id");
            Invoice invoice = invoiceManager.getInvoice(id);

            if (request.getParameter("cancel") != null) {
                response.sendRedirect(request.getContextPath());
                return;
            }
            StringBuilder errors = new StringBuilder();
            SimpleDateFormat foramtter = new SimpleDateFormat("dd/MM/yyyy");
            request.setAttribute("niceInvoicingDate", foramtter.format(invoice.getInvoicingDate()));
            request.setAttribute("niceDueDate", foramtter.format(invoice.getDueDate()));
            request.setAttribute(ATTRIBUTE_ERROR, errors.toString());
            request.setAttribute(ATTRIBUTE_EDIT_INVOICE, invoice);
            request.getRequestDispatcher(JSP_EDIT_ATTRIBUTES_INVOICE).forward(request, response);

            // response.sendRedirect(request.getContextPath());
        }
        if (request.getMethod().equals("POST")) {
            if (request.getParameter("cancel") != null) {
                response.sendRedirect(request.getContextPath());
                return;
            }
            StringBuilder errors = new StringBuilder();
            InvoiceForm invoiceForm = InvoiceForm.extractFromRequest(request);
            Invoice invoice = invoiceForm.validateAndToInvoice(errors);

            if (invoice == null) {

                request.setAttribute(ATTRIBUTE_ERROR, errors.toString());
                request.setAttribute(ATTRIBUTE_EDIT_INVOICE, invoiceForm);
                request.getRequestDispatcher(JSP_EDIT_ATTRIBUTES_INVOICE).forward(request, response);
            } else {
                invoice.setId(request.getParameter("id"));
                invoiceManager.updateInvoice(invoice);
                response.sendRedirect(request.getContextPath());
            }
        }
    }
/*
 * Method which lists invoices from database for further removing.
 * @param request request from page
 * @param response response to page
 * @throws ServletException
 * @throws IOException 
 */
    private void removeInvoice(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setAttribute(ATTRIBUTE_INVOICES, invoiceManager.getInvoicesForPeriod(new Date(Long.MIN_VALUE), new Date(Long.MAX_VALUE)));
        request.getRequestDispatcher(JSP_REMOVE_INVOICE).forward(request, response);
    }
/*
 * Method which ask user to confirm deleting of invoice from database. 
 * @param request request from page
 * @param response response to page
 * @throws ServletException
 * @throws IOException 
 */
    private void confirmRemoveInvoice(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        if (request.getMethod().equals("GET")) {
            String id = request.getParameter("id");
            Invoice invoice = invoiceManager.getInvoice(id);

            if (request.getParameter("cancel") != null) {
                response.sendRedirect(request.getContextPath());
                return;
            }
            StringBuilder errors = new StringBuilder();
            SimpleDateFormat foramtter = new SimpleDateFormat("dd/MM/yyyy");
            request.setAttribute("niceInvoicingDate", foramtter.format(invoice.getInvoicingDate()));
            request.setAttribute("niceDueDate", foramtter.format(invoice.getDueDate()));
            request.setAttribute(ATTRIBUTE_ERROR, errors.toString());
            request.setAttribute(ATTRIBUTE_EDIT_INVOICE, invoice);
            request.getRequestDispatcher(JSP_CONFIRM_REMOVE_INVOICE).forward(request, response);

            //response.sendRedirect(request.getContextPath());
        }
        if (request.getMethod().equals("POST")) {
            if (request.getParameter("cancel") != null) {
                response.sendRedirect(request.getContextPath());
                return;
            }
            StringBuilder errors = new StringBuilder();
            invoiceManager.removeInvoice(request.getParameter("id"));
            response.sendRedirect(request.getContextPath());
        }
    }
/*
 * Method for list invoices in databse. 
 * @param request request from page
 * @param response response to page
 * @throws ServletException
 * @throws IOException 
 */
    private void showInvoices(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
        request.setAttribute(ATTRIBUTE_INVOICES, invoiceManager.getInvoicesForPeriod(sdf.parse(request.getParameter("fromDate")), sdf.parse(request.getParameter("toDate"))));
        request.getRequestDispatcher(JSP_SHOW_INVOICES).forward(request, response);
    }
/*
 * Method which prepate tax for user.
 * @param request request from page
 * @param response response to page
 * @throws ServletException
 * @throws IOException 
 */
    private void invoiceDetail(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String id = request.getParameter("id");
        String transformedXml = invoiceManager.getInvoiceAsHTML(id);
        if (request.getParameter("cancel") != null) {
            response.sendRedirect(request.getContextPath());
            return;
        }
        StringBuilder errors = new StringBuilder();
        request.setAttribute(ATTRIBUTE_ERROR, errors.toString());
        request.setAttribute(ATTRIBUTE_TRANSFORMED_XML, transformedXml);
        request.getRequestDispatcher(JSP_INVOICE_DETAIL).forward(request, response);
    }

    private void prepareTax(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException, ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
        int year = Calendar.getInstance().get(Calendar.YEAR);
        year--;
        request.setAttribute(ATTRIBUTE_YEAR, year);
        request.setAttribute(ATTRIBUTE_SUM_PAYMENTS, paymentManager.paymentSum(sdf.parse("01/01/" + year), sdf.parse("31/12/" + year)));
        request.setAttribute(ATTRIBUTE_SUM_INVOICES, invoiceManager.sumOfInvoicesForPeriod(sdf.parse("01/01/" + year), sdf.parse("31/12/" + year)));
        request.getRequestDispatcher(JSP_PREPARE_TAX).forward(request, response);
    }
/*
 * Method for handling requests from pages. 
 * @param request request from page
 * @param response response to page
 * @throws ServletException
 * @throws IOException 
 */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException, ParseException {
        response.setContentType("text/html;charset=UTF-8");
        String path = request.getServletPath();
        if (path.equals(ACTION_ADD_PAYMENT)) {
            addPayment(request, response);
        } else if (path.equals(ACTION_EDIT_PAYMENT)) {
            editPayment(request, response);
        } else if (path.equals(ACTION_REMOVE_PAYMENT)) {
            removePayment(request, response);
        } else if (path.equals(ACTION_EDIT_ATTRIBUTES)) {
            editAttributes(request, response);
        } else if (path.equals(ACTION_SHOW_PAYMENTS)) {
            showPayments(request, response);
        } else if (path.equals(ACTION_EDIT_ATTRIBUTES_INVOICE)) {
            editAttributesInvoice(request, response);
        } else if (path.equals(ACTION_ADD_INVOICE)) {
            addInvoice(request, response);
        } else if (path.equals(ACTION_EDIT_INVOICE)) {
            editInvoice(request, response);
        } else if (path.equals(ACTION_REMOVE_INVOICE)) {
            removeInvoice(request, response);
        } else if (path.equals(ACTION_SHOW_INVOICES)) {
            showInvoices(request, response);
        } else if (path.equals(ACTION_PREPARE_TAX)) {
            prepareTax(request, response);
        } else if (path.equals(ACTION_CONFIRM_REMOVE_PAYMENT)) {
            confirmRemovePayment(request, response);
        } else if (path.equals(ACTION_CONFIRM_REMOVE_INVOICE)) {
            confirmRemoveInvoice(request, response);
        } else if (path.equals(ACTION_INVOICE_DETAIL)) {
            invoiceDetail(request, response);
        } else {
            throw new RuntimeException("Unknown operation: " + request.getServletPath());
        }
    }
    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">

    /**
     * Handles the HTTP
     * <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            processRequest(request, response);
        } catch (ParseException ex) {
            Logger.getLogger(ActionServlet.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Handles the HTTP
     * <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        try {
            processRequest(request, response);
        } catch (ParseException ex) {
            Logger.getLogger(ActionServlet.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>
}
